home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume2 / sys5-fs-analysis < prev    next >
Encoding:
Internet Message Format  |  1991-08-07  |  40.4 KB

  1. From: mjy@sdti.UUCP (Michael J. Young)
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i005: File System Analyzer Tool
  4. Message-ID: <7079@ncoast.UUCP>
  5. Date: 15 Jan 88 00:31:36 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. Comp.Sources.Misc: Volume 2, Issue 5
  9. Submitted-By: Michael J. Young <mjy@sdti.UUCP>
  10. Archive-Name: sys5-fs-analysis
  11.  
  12. I've tried posting this to comp.sources.unix a number of times (since
  13. October!), but I seem to have discovered a black hole between here and that
  14. newsgroup.  Since I'm starting to get gentle reminders that I'd promised
  15. this awhile ago, I decided to punt and try posting here.
  16.  
  17. This is a tool that I wrote to determine file system fragmentation on my
  18. Microport box.  I mentioned it a few months ago in comp.unix.wizards, and
  19. got a lot of requests for the source.  It's not very elegant, and it's
  20. specific to System V, but it's functional.
  21.  
  22. I'd really like to see it ported to other systems (I only have access to
  23. System V).  If anyone has lots of spare time(!)  and wants to port it, there
  24. are some notes in the README file for things to watch out for.  Please send
  25. me your changes so I can incorporate them into my version.  If you are
  26. really bored, feel free to add an in-place disk-compression capability! :-)
  27.  
  28. --------------------- cut here -------- cut here --------------------------
  29. #! /bin/sh
  30. # This is a shell archive.  Remove anything before this line, then unpack
  31. # it by saving it into a file and typing "sh file".  To overwrite existing
  32. # files, type "sh file -c".  You can also feed this as standard input via
  33. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  34. # will see the following message at the end:
  35. #        "End of archive 1 (of 1)."
  36. # Contents:  README fsanalyze.8 fsanalyze.c
  37. # Wrapped by mjy@sdti on Thu Jan  7 15:46:01 1988
  38. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  39. if test -f README -a "${1}" != "-c" ; then 
  40.   echo shar: Will not over-write existing file \"README\"
  41. else
  42. echo shar: Extracting \"README\" \(7915 characters\)
  43. sed "s/^X//" >README <<'END_OF_README'
  44. XFSANALYZE - System V File System Analyzer tool - v2.04, 7 Januaray 1988
  45. X
  46. XAuthor   : Michael J. Young
  47. XUSmail   : Software Development Technologies, Inc.
  48. X           375 Dutton Rd
  49. X           Sudbury MA  01776
  50. XUUCP     : {decvax|harvard|linus|mit-eddie}!necntc!necis!mrst!sdti!mjy
  51. XInternet : mjy%sdti.uucp@harvard.harvard.edu
  52. X
  53. X   =========================================================================
  54. X   Note : This program has been placed in the public domain to permit
  55. X   unrestricted distribution and use.  I have placed no copyright on it, but
  56. X   I request that you keep me informed about any enhancements and bug fixes
  57. X   you make so I can keep an up-to-date copy for further distribution.
  58. X   =========================================================================
  59. X
  60. X   Fsanalyze is a simple tool that estimates file system fragmentation.  It
  61. X   accomplishes this by scanning the data blocks for each i-node in the 
  62. X   file system, looking for block numbers that are out of sequence.  In
  63. X   effect, it is counting the number of disk seeks required to read the
  64. X   entire file in sequence.  Fragmentation is then computed as the ratio
  65. X   of actual "seeks" to the potential number of "seeks" if the file were
  66. X   completely fragmented.
  67. X
  68. X   Fsanalyze also provides statistics regarding the number (and identity) of
  69. X   files that are very large, and excessively large directories.
  70. X   
  71. X   Excessively large directories are directories that are over 5120 bytes
  72. X   long (320 entries).  Directories larger than this require data block
  73. X   indirection, making file searches very inefficient.
  74. X
  75. X   After the general file system statistics are displayed, fsanalyze lists
  76. X   the 10 most fragmented i-nodes in the file system.  
  77. X   The 10 most fragmented files are listed in decreasing order of 
  78. X   fragmentation based on the absolute number of fragments.  For example,
  79. X   a 100-block file that contains 40 individual fragments is 39.39%
  80. X   fragmented (39 seeks / 99 potential seeks), but is listed before
  81. X   a 2-block file that contains 2 fragments (100% fragmented).  Thus, larger
  82. X   fragmented files (which have a greater effect on file system performance)
  83. X   are listed before small files.
  84. X
  85. XRevision History:
  86. X
  87. X   Version 2.0 is a major rewrite of fsanalyze that adds the following new
  88. X   features:
  89. X       - The ability to analyze individual files
  90. X       - Display of the 10 most fragmented files in a file system
  91. X       - Enhanced error checking on the file system argument
  92. X
  93. X   Version 2.01 contains a minor modification in which fsanalyze executes
  94. X   /etc/fsstat to determine the health of the file system before analyzing
  95. X   it.
  96. X
  97. X   Version 2.02 contains a minor modification to print out a warning message
  98. X   if the file system being analyzed is currently mounted.
  99. X
  100. X   Version 2.03 contains a fix for a minor bug in which the size of the
  101. X   volume data block size would be printed out incorrectly for large
  102. X   file systems.
  103. X
  104. X   Version 2.04 incorporates the library function l3tol to access inode
  105. X   block numbers.
  106. X
  107. XInstallation:
  108. X
  109. X   This program is so simple that I didn't bother to create a Makefile.  To
  110. X   build fsanalyze the steps are:
  111. X      cc -O -o fsanalyze fsanalyze.c
  112. X      mv fsanalyze /bin
  113. X   Where fsanalyze is installed doesn't really matter, but I would recommend
  114. X   placing it somewhere in the root filesystem, which is always mounted.  I
  115. X   typically run fsanalyze during my backup procedure, while my other
  116. X   filesystems are unmounted.
  117. X
  118. XUsage:
  119. X   fsanalyze [-flags] special [file [...]]
  120. X
  121. X   If the optional filename arguments are missing, the entire file system
  122. X   is analyzed.  If present, the specified files are analyzed and reported
  123. X   individually.
  124. X
  125. X   [flags] include the following:
  126. X     d   display i-node numbers as they are examined
  127. X     e   report file size inconsistencies - the inode numbers are reported
  128. X         for files where the file size and number of data blocks are
  129. X         inconsistent.
  130. X     i   report double and triple indirection - the inode numbers are
  131. X         reported for files that contain double and/or triple indirection.
  132. X     o   overrides error checking on file system.  Use this flag if the
  133. X         file system you are analyzing is damaged.  Note that fsanalyze
  134. X         may give erroneous results if used on a damaged file system, but
  135. X         the file system itself will not be affected.
  136. X
  137. X   Example:
  138. X     fsanalyze /dev/dsk/0s2    /* analyzes an entire file system */
  139. X     fsanalyze /dev/dsk/0s2 *    /* analyzes all files in the current
  140. X                                 * directory of the file system */
  141. X
  142. X   Since fsanalyze uses the superblock info ON THE DISK, more accurate
  143. X   results will be returned fsanalyze is run on an unmounted, or read-only
  144. X   mounted file system immediately after a sync(2).
  145. X
  146. X   Note that fsanalyze will work with 512- or 1024-byte filesystems.  In
  147. X   filesystems with 1024-byte blocking-factors, free-blocks, etc., are
  148. X   reported as 1024-byte blocks (unlike df(1) and du(1)).  Therefore, the total
  149. X   number of free blocks in your file system will be reported as half the
  150. X   value reported by df(1).  I prefer it this way.  If you want it the
  151. X   other way, it requires a simple change to print_report().
  152. X
  153. X   Since fsanalyze does its work the old fashioned way (brute-force), it
  154. X   must scan through the file system inode by inode.  It therefore takes
  155. X   about as long as fsck to do its work.  Be patient.
  156. X
  157. XBugs:
  158. X   Please report any bugs (and possible fixes) to me, so I can keep my
  159. X   source up-to-date.  I would also like to make fsanalyze work on other
  160. X   unix systems, but I don't have access to anything but my little 
  161. X   uport.  If you can help me port it to BSD or anything else, I would
  162. X   appreciate it.
  163. X
  164. XPorting fsanalyze to other systems:
  165. X   Fsanalyze takes its information on the structure of the file system
  166. X   from /usr/include/sys/filsys.h and /usr/include/sys/ino.h.  As long
  167. X   as these files (or equivalent) are present on your system, porting
  168. X   should be straightforward.  When looking for the equivalent of these
  169. X   files on your system, be sure to get the disk-based versions, rather
  170. X   than the in-memory structures -- they are different.  In System V
  171. X   derivatives, these structures should be documented as fs(4 or 5) and
  172. X   inode(4 or 5), on BSD systems and V7 systems as filsys(5), and on
  173. X   XENIX 3.0 and 5.0 as filesystem(F).
  174. X
  175. X   Fsanalyze uses fsstat(1M) to determine file system integrity.  I don't
  176. X   think this program is available in other versions of Unix.  If your
  177. X   system doesn't have it (or anything like it), you will have to rewrite
  178. X   check_fs().  The kinds of things to check when testing for file system
  179. X   integrity include:
  180. X    1.  Make sure the device is block structured.
  181. X    2.  Determine whether or not the device is mounted.
  182. X    3.  Check s_state in the filsys structure to see if it is in a
  183. X        known state.
  184. X    4.  Anying else you can think of.
  185. X   I used fsstat because it seems to be more robust than anything I
  186. X   could come up with.  It also appears to use undocumented information
  187. X   to determine file system status.
  188. X
  189. X   fsstat(1M) returns 0 if the file system is ok, 1 if it needs to be
  190. X   checked, 2 if it is mounted, and 3 for other errors.  Unfortunately,
  191. X   the exit status appears to be byte-swapped when fsanalyze gets it.
  192. X   I'm not sure if this is a bug in system(3S), or my use of it, but
  193. X   be careful when porting to your system.
  194. X  
  195. X   I attempted to use types defined in /usr/include/sys/types.h wherever
  196. X   possible to ensure portability.  I don't think I made any assumptions
  197. X   about sizeof(int) == sizeof(long) == sizeof(char *), so there should
  198. X   be no problems there.
  199. X
  200. X   Please try to make changes to the source using #defines and #ifdefs
  201. X   wherever possible, and please email me the changes you make along with
  202. X   a description of the system you ported it to (and problems encountered),
  203. X   so I can merge all the changes into a single copy.
  204. X
  205. X   Thanks and good luck!
  206. END_OF_README
  207. if test 7915 -ne `wc -c <README`; then
  208.     echo shar: \"README\" unpacked with wrong size!
  209. fi
  210. # end of overwriting check
  211. fi
  212. if test -f fsanalyze.8 -a "${1}" != "-c" ; then 
  213.   echo shar: Will not over-write existing file \"fsanalyze.8\"
  214. else
  215. echo shar: Extracting \"fsanalyze.8\" \(3441 characters\)
  216. sed "s/^X//" >fsanalyze.8 <<'END_OF_fsanalyze.8'
  217. X.TH FSANALYZE 8
  218. X.ad b
  219. X.SH NAME
  220. Xfsanalyze \- a file system analyzer tool
  221. X.SH SYNOPSIS
  222. X.B fsanalyze
  223. X[
  224. X.B \-deio
  225. X]
  226. X.B special
  227. X[
  228. X.B files
  229. X]
  230. X.SH DESCRIPTION
  231. X.I Fsanalyze
  232. Xis a simple tool that estimates file or file system fragmentation.  It accomplishes
  233. Xthis by scanning the data blocks of each inode looking for block numbers that
  234. Xare out of sequence.  In effect, it is counting the number of disk seeks
  235. Xrequired to read a file sequentially.  Fragmentation is then computed as the
  236. Xratio of actual "seeks" to the potential number "seeks" which would be
  237. Xrequired if the file were completely fragmented.
  238. X.LP
  239. XIf the optional \fBfiles\fR argument is omitted,
  240. X.I fsanalyze
  241. Xwill analyze the entire file system specified by the \fBspecial\fR argument.
  242. X\fBSpecial\fR must be a block-oriented file system device.
  243. X.I Fsanalyze
  244. Xreports various statistics regarding file system usage and data-block
  245. Xindirection, plus a list of the 10 most fragmented inodes in the file system.
  246. XThe 10 most fragmented files are listed in decreasing order of fragmentation
  247. Xbased on the absolute number of fragments.  For example a 100-block file
  248. Xthat contains 40 individual fragments is 39.39% fragmented (39 seeks / 99
  249. Xpotential seeks), but is listed before a 2-block file that contains 2
  250. Xfragments (100% fragmented).
  251. X.LP
  252. XIf the \fBfiles\fR argument is present,
  253. X.I fsanalyze
  254. Xwill report the fragmentation of the designated files only.
  255. X.LP
  256. XBefore performing any analysis,
  257. X.I fsanalyze
  258. Xchecks the file system integrity by invoking
  259. X.I fsstat (1M).
  260. XIf the file system needs to be checked,
  261. X.I fsanalyze
  262. Xterminates with a message to that effect.  If a non-root file system is
  263. Xmounted, a warning message is displayed, but analysis continues.  When
  264. Xused on a mounted file system, it is recommended that a
  265. X.I sync (1)
  266. Xbe performed immediately prior to running
  267. X.I fsanalyze .
  268. XIf
  269. X.I sync (1)
  270. Xis not performed, the file system will not be damaged, but erroneous
  271. Xstatistics may be reported.
  272. X.SH OPTIONS
  273. X.IP \fB\-d\fR
  274. Xdisplay inode numbers as they are examined.  This flag makes it easy to
  275. Xchart the progress of fsanalyze through the file system.  Used mainly for
  276. Xdebugging.
  277. X.IP \fB\-e\fR
  278. Xreport file size inconsistencies - the inode numbers are reported for files
  279. Xwhere the file size and number of data blocks are inconsistent.  This
  280. Xoption provides the same information as
  281. X.I fsck (1)
  282. Xphase 1.
  283. X.IP \fB\-i\fR
  284. Xreport double and triple indirection - the inode numbers are reported for
  285. Xfiles that contain double and/or triple data-block indirection.
  286. X.IP \fB\-o\fR
  287. Xoverrides file system integrity checks.  The file system will be analyzed
  288. Xeven if
  289. X.I fsstat (1M)
  290. Xreports that it is damaged.  Note that
  291. X.I fsanalyze
  292. Xmay give erroneous results if used on a damaged file system, but the file
  293. Xsystem itself will not be affected.
  294. X.SH EXAMPLES
  295. Xfsanalyze /dev/dsk/0s2    # analyze file system
  296. X.br
  297. Xfsanalyze /dev/dsk/0s2 *  # analyze files in current dir
  298. X.SH FILES
  299. X/usr/include/sys/filesys.h    super block structure
  300. X.br
  301. X/usr/include/sys/ino.h        disk inode structure
  302. X.br
  303. X/usr/include/sys/param.h    system parameters
  304. X.br
  305. X/usr/include/sys/types.h    system type definitions
  306. X.SH BUGS
  307. X.I Fsanalyze
  308. Xis supported by System V Release 2.  It has not yet been ported to any
  309. Xother version of Unix.
  310. X.SH "SEE ALSO"
  311. Xfsstat(1M), fsck(1M), fsdb(1M)
  312. X.SH AUTHOR
  313. XMichael J. Young
  314. X.br
  315. X{decvax|harvard|linus|mit-eddie}!necntc!necis!mrst!sdti!mjy
  316. X.br
  317. XInternet : mjy%sdti.uucp@harvard.harvard.edu
  318. X.SH VERSION
  319. Xv2.04 \- 7 January 1988
  320. END_OF_fsanalyze.8
  321. if test 3441 -ne `wc -c <fsanalyze.8`; then
  322.     echo shar: \"fsanalyze.8\" unpacked with wrong size!
  323. fi
  324. # end of overwriting check
  325. fi
  326. if test -f fsanalyze.c -a "${1}" != "-c" ; then 
  327.   echo shar: Will not over-write existing file \"fsanalyze.c\"
  328. else
  329. echo shar: Extracting \"fsanalyze.c\" \(25225 characters\)
  330. sed "s/^X//" >fsanalyze.c <<'END_OF_fsanalyze.c'
  331. X/*
  332. X * fsanalyze.c - file system analyzer - v2.04; 7 January 1988
  333. X *
  334. X * Author   : Michael J. Young
  335. X * USmail   : Software Development Technologies, Inc.
  336. X *            375 Dutton Rd
  337. X *            Sudbury MA 01776
  338. X * UUCP     : {decvax|harvard|linus|mit-eddie}!necntc!necis!mrst!sdti!mjy
  339. X * Internet : mjy%sdti.uucp@harvard.harvard.edu
  340. X *
  341. X * =========================================================================
  342. X * Note : This program has been placed in the public domain to permit
  343. X * unrestricted distribution and use.  I have placed no copyright on it, but
  344. X * I request that you keep me informed about any enhancements and bug fixes
  345. X * you make so I can keep an up-to-date copy for further distribution.
  346. X * =========================================================================
  347. X *
  348. X * fsanalyze is a simple tool that estimates file system fragmentation.  It
  349. X * accomplishes this by scanning the data blocks for each i-node in the 
  350. X * file system, looking for block numbers that are out of sequence.  
  351. X * Fragmentation is then computed as the ratio of out-of-sequence blocks to
  352. X * total data blocks.
  353. X * 
  354. X * fsanalyze also provides statistics regarding the number (and identity) of
  355. X * files that are very large, and especially excessively large directories 
  356. X * (which are very inefficient).
  357. X * 
  358. X * To build fsanalyze the steps are:
  359. X *       cc -O -o fsanalyze fsanalyze.c
  360. X *       mv fsanalyze /bin
  361. X *
  362. X * Usage:
  363. X *    fsanalyze [-flags] special [file] ...
  364. X *
  365. X *    where [flags] include the following:
  366. X *      d   display i-node numbers as they are examined
  367. X *      e   report file size inconsistencies
  368. X *      i   report inodes numbers with double and triple indirection
  369. X *    o   override error checking on file system superblock
  370. X *
  371. X *    If the optional file argument(s) are present, only the specified
  372. X *    individual files on the file system are analyzed.  If absent, the
  373. X *    entire file system is analyzed.
  374. X *
  375. X *    Example:
  376. X *      fsanalyze /dev/dsk/0s2
  377. X *
  378. X *    Since fsanalyze uses the superblock info ON THE DISK, more accurate
  379. X *    results will be returned if sync(1) is executed immediately prior to
  380. X *    fsanalyze.
  381. X */
  382. X
  383. X/*
  384. X * Modification History:
  385. X *
  386. X *    Date       Author                   Description
  387. X * -----------  --------  -----------------------------------------------
  388. X * 28 Jul 1987    MJY       Originated
  389. X *  5 Oct 1987    MJY       Capability to analyze individual files,
  390. X *                Added error checking to file system argument,
  391. X *                Added -o flag
  392. X *                Prints out volume and file system name in summary
  393. X * 12 Oct 1987    MJY       Use /etc/fsstat to do file system validity
  394. X *                          checking
  395. X *  9 Nov 1987    MJY       print out warning if file system is mounted
  396. X * 12 Nov 1987    MJY       Volume size statistics now long instead of int
  397. X *  7 Jan 1988    MJY       Modified blk_no() to use l3tol()
  398. X */
  399. X
  400. X
  401. X# include <stdio.h>
  402. X# include <sys/types.h>
  403. X# include <sys/ino.h>
  404. X# include <sys/param.h>
  405. X# include <sys/filsys.h>
  406. X# include <sys/stat.h>
  407. X
  408. X# define BLK_SIZE    512        /* block size */
  409. X# define IBLK         2        /* block number of first i-node */
  410. X
  411. X# define I_BLOCK_FACTOR    32        /* number of i-nodes per block */
  412. X
  413. X/*
  414. X * file mode definitions
  415. X */
  416. X# define FILE_TYPE(a)     ((a)->di_mode & S_IFMT)
  417. X# define IS_SPECIAL(a)    (((a) & S_IFMT == S_IFBLK) || ((a) & S_IFMT == S_IFCHR) || ((a) & S_IFMT == S_IFIFO))
  418. X
  419. X/*
  420. X * basic definitions
  421. X */
  422. X# define FALSE    0
  423. X# define TRUE    1
  424. X
  425. Xtypedef int boolean;
  426. X
  427. X/*
  428. X * per-file statistics structure
  429. X */
  430. Xstruct file_data {
  431. X    int inode;            /* i-node number */
  432. X    long total_blocks;        /* total blocks in file (incl 
  433. X                     * indirect blocks */
  434. X    long data_blocks;        /* total data blocks in file */
  435. X    long potential_seeks;        /* number of potential seeks in file */
  436. X    long seeks;            /* actual seeks in file */
  437. X    float fragm;            /* fragmentation (seeks/pot.seeks) */
  438. X    };
  439. X
  440. XFILE *fsys               = NULL;    /* file system under test */
  441. Xchar *special            = NULL;    /* file system device name */
  442. X
  443. X/*
  444. X * file system static data
  445. X */
  446. Xstruct filsys super      = {0};        /* holds file system super block */
  447. Xint fs_type              = 1;        /* file system logical block size
  448. X                     * (in 512 byte units) */
  449. Xlong num_inodes          = 0;        /* number of i-nodes in file system */
  450. X
  451. X/*
  452. X * calculated global statistics
  453. X */
  454. Xlong blocks              = 0;        /* running block count */
  455. Xlong free_inodes         = 0;        /* number of unused i-nodes */
  456. Xlong potential_seeks     = 0;        /* potential number of disk seeks
  457. X                     * during sequential access of a 
  458. X                     * file */
  459. Xlong seeks               = 0;        /* actual number of disk seeks
  460. X                     * required during sequential access
  461. X                     * of a file */
  462. Xlong indirects           = 0;        /* number of files w/ more than
  463. X                     * 10 data blocks */
  464. Xlong double_indirects    = 0;        /* number of files w/ more than
  465. X                    /* one level of indirection */
  466. Xlong triple_indirects    = 0;        /* number of files w/ more than
  467. X                     * two levels of indirection */
  468. Xint big_directories      = 0;        /* number of directories with
  469. X                     * indirection */
  470. Xint num_directories      = 0;        /* number of directories */
  471. Xint linked_files         = 0;        /* number of multiply-linked files */
  472. Xint size_errors          = 0;        /* number of file size discrepancies */
  473. X
  474. X
  475. Xstruct file_data file_log[10] = {0};        /* 10 worst offenders */
  476. X
  477. X
  478. X/*
  479. X * fsanalyze command-line flags
  480. X */
  481. Xboolean report_indirects = FALSE;    /* command line option -- report
  482. X                     * files with indirect data blocks */
  483. Xboolean report_errors    = FALSE;    /* command line option -- report
  484. X                     * file size discrepancies */
  485. Xboolean debug            = FALSE;    /* report i-node #s as they are
  486. X                     * examined */
  487. Xboolean override     = FALSE;    /* override bad fs test */
  488. X
  489. X
  490. X/*
  491. X * interface to system error messages
  492. X */
  493. Xextern int errno;
  494. Xextern char *sys_errlist[];
  495. Xextern int sys_nerr;
  496. X
  497. X/*
  498. X * usage : prints out a short message describing command usage.  This
  499. X * function does not return.
  500. X */
  501. Xvoid usage(){
  502. X    printf ("File System analyzer - v2.01\n");
  503. X    printf ("Usage:\n   fsanalyze [-[deio]] special [file] ...\n");
  504. X    printf ("\n\tIf the [file] argument(s) are missing, the entire\n");
  505. X    printf ("\tfile system is scanned.  Otherwise, only the specified\n");
  506. X    printf ("\tfiles are examined.  Valid flag are:\n\n");
  507. X    printf ("\td\tdisplay i-node numbers as they are examined\n");
  508. X    printf ("\te\treport file size inconsistencies\n");
  509. X    printf ("\ti\treport data block double and triple indirection\n");
  510. X    printf ("\to\toverride error checking on file system argument\n");
  511. X    exit(1);
  512. X    }
  513. X
  514. X/*
  515. X * check_fs : checks the file system to be sure it is not in need of
  516. X * checking.  If the file system is damaged, the function displays a
  517. X * message from fsstat, then returns FALSE.  Othersize, returns TRUE.
  518. X */
  519. Xboolean check_fs (special)
  520. Xchar *special;
  521. X{
  522. X    char buffer[256];            /* buffer to hold cmd */
  523. X    int fstat;                /* exit status of fsstat */
  524. X
  525. X    sprintf (buffer, "/etc/fsstat %s 2>/dev/null", special);
  526. X    fstat = system (buffer);
  527. X    if (fstat != 0 && !override){
  528. X        if (fstat == 512 /* why is this byte-swapped? */){
  529. X            fprintf (stderr, "warning: file system is mounted\n");
  530. X            }
  531. X        else {
  532. X            /*
  533. X             * run fsstat again to get error message (this is a kludge,
  534. X             * but I hope more portable that having fsanalyze do the
  535. X             * analysis itself)
  536. X             */
  537. X            sprintf (buffer, "/etc/fsstat %s", special);
  538. X            system(buffer);
  539. X            return (FALSE);
  540. X            }
  541. X        }
  542. X    return (TRUE);
  543. X    }
  544. X
  545. X/*
  546. X * error : prints out a formatted error string to stderr, followed if
  547. X * possible by an appropriate system error message.  Control is then
  548. X * returned to the system with an error status.  This function does not
  549. X * return.
  550. X */
  551. Xvoid error (err, str, arg1, arg2)
  552. Xint err;            /* value of errno at time of call */
  553. Xchar *str;            /* error string */
  554. Xchar *arg1, *arg2;        /* additional printf arguments, if any */
  555. X{
  556. X    fprintf (stderr, str, arg1, arg2);
  557. X    if (err <= sys_nerr && err > 0)
  558. X        fprintf (stderr, "%s\n", sys_errlist[err]);
  559. X    else
  560. X        fprintf (stderr, "unknown error : %d\n", err);
  561. X    exit(1);            /* exit with error status */
  562. X    }
  563. X
  564. X/*
  565. X * init_stats : initializes per-file statistics structure
  566. X */
  567. Xvoid init_stats (data, inode)
  568. Xstruct file_data *data;                /* file stats to init */
  569. Xint inode;                    /* i-node number */
  570. X{
  571. X    data->inode = inode;
  572. X    data->total_blocks = data->data_blocks = 0;
  573. X    data->potential_seeks = data->seeks = 0;
  574. X    data->fragm = 0.0;
  575. X    }
  576. X
  577. X/*
  578. X * init : parses command line flags and the file system device name, then
  579. X * reads the file system super block.  init returns the number of the
  580. X * parameter AFTER the file system device name.  All subsequent parameters
  581. X * are assumed to be specific files to be tested.
  582. X */
  583. Xint init (argc, argv)
  584. Xint argc;
  585. Xchar *argv[];
  586. X{
  587. X    int i;                    /* loop counter */
  588. X    char *cp;                /* cmd-line flag pointer */
  589. X    boolean special_found = FALSE;        /* TRUE = found special arg */
  590. X    
  591. X    for (i = 1; i < argc && !special_found; i++){
  592. X        cp = argv[i];
  593. X        if (*cp == '-'){
  594. X            while (*++cp){
  595. X                switch (*cp){
  596. X
  597. X                        /* report i-nodes with
  598. X                         * one or more levels of
  599. X                         * indirection */
  600. X                    case 'i':
  601. X                        report_indirects = TRUE;
  602. X                        break;
  603. X
  604. X                        /* report file size errors */
  605. X                    case 'e':
  606. X                        report_errors = TRUE;
  607. X                        break;
  608. X
  609. X                        /* debugging flag */
  610. X                    case 'd':
  611. X                        debug = TRUE;
  612. X                        break;
  613. X
  614. X                        /* override bad fs test */
  615. X                    case 'o':
  616. X                        override = TRUE;
  617. X                        break;
  618. X                    default:
  619. X                        fprintf (stderr, "illegal option : %c\n", *cp);
  620. X                        usage();
  621. X                    }
  622. X                }
  623. X            }
  624. X        else {
  625. X            special = argv[i];
  626. X            special_found = TRUE;
  627. X            }
  628. X        }
  629. X    if (special == NULL)usage();        /* no fs parameter */
  630. X
  631. X    /*
  632. X     * check for good file system (let fsstat do the dirty work!)
  633. X     */
  634. X    if (check_fs (special)){
  635. X
  636. X        /*
  637. X         * open file system and read the super block
  638. X         */
  639. X        if ((fsys=fopen (special, "r")) == NULL){
  640. X            error (errno, "error opening \"%s\"\n", special);
  641. X            /* NOTREACHED */
  642. X            }
  643. X        if (fseek (fsys, 512L, 0)){
  644. X            error (errno, "error seeking superblock");
  645. X            /* NOTREACHED */
  646. X            }
  647. X        if (fread (&super, sizeof (struct filsys), 1, fsys) != 1){
  648. X            error (errno, "error reading superblock");
  649. X            /* NOTREACHED */
  650. X            }
  651. X
  652. X        num_inodes = (super.s_isize-2) * 16;
  653. X        if (super.s_magic != FsMAGIC)
  654. X            fs_type = Fs1b;
  655. X        else fs_type = super.s_type;
  656. X
  657. X        return i;        /* return # of next argument to be processed */
  658. X        }
  659. X    else {
  660. X        exit(1);        /* bad file system, error status */
  661. X        }
  662. X    }
  663. X
  664. X/*
  665. X * blk_no : given a pointer to a 3-byte binary number, returns a (long)
  666. X * block number.  Used to access the first 10 data block numbers of an
  667. X * i-node.  The function l3tol is used for portability.
  668. X */
  669. Xdaddr_t blk_no (off)
  670. Xunsigned char off[];                /* 3-byte offset */
  671. X{
  672. X    extern void l3tol();
  673. X    daddr_t temp = 0;
  674. X    int n;
  675. X
  676. X    l3tol (&temp, off, 1);
  677. X    return temp;
  678. X    }
  679. X
  680. X/*
  681. X * get_inodes : given an initial i-node number, reads a block of i-nodes
  682. X * into an i-node array.
  683. X */
  684. Xvoid get_inodes (in, inp, num)
  685. Xint in;                        /* inode number */
  686. Xint num;                    /* # inodes to get */
  687. Xstruct dinode *inp;                /* buffer to hold info */
  688. X{
  689. X    long position;                /* computed position of the
  690. X                         * first requested i-node */
  691. X
  692. X    position = (IBLK * BLK_SIZE * fs_type) + 
  693. X           (sizeof (struct dinode) * ((long)in-1));
  694. X
  695. X    if (fseek (fsys, position, 0)){
  696. X        error (errno, "\nerror seeking inode %d, pos = %ld\n", in, position);
  697. X        /* NOTREACHED */
  698. X        }
  699. X    else {
  700. X        if (fread (inp, sizeof (struct dinode), num, fsys) != num){
  701. X            error (errno, "\nerror reading inode %d\n", in);
  702. X            /* NOTREACHED */
  703. X            }
  704. X        }
  705. X    }
  706. X
  707. X/*
  708. X * check_indirects : scans a block containing data block numbers, looking
  709. X * for block numbers that are not sequential.
  710. X */
  711. Xdaddr_t check_indirects (block, cur_pos, data)
  712. Xdaddr_t block;                    /* indirect block to check */
  713. Xdaddr_t cur_pos;                /* current block offset */
  714. Xstruct file_data *data;                /* current file statistics */
  715. X{
  716. X    daddr_t indirect_blk[256];        /* holds an indirect block */
  717. X    int num_blocks;                /* number of data blocks in
  718. X                         * an indirect block */
  719. X    daddr_t pos;                /* current data block */
  720. X    daddr_t new_pos;            /* next data block */
  721. X    int i;                    /* loop counter */
  722. X
  723. X    num_blocks = 128 * fs_type;
  724. X    data->total_blocks++;
  725. X
  726. X    /*
  727. X     * get the indirect block
  728. X     */
  729. X    if (fseek (fsys, block * 512L * fs_type, 0)){
  730. X        error (errno, "\nerror seeking indirect block %ld\n", block);
  731. X        /* NOTREACHED */
  732. X        }
  733. X    if (fread (indirect_blk, sizeof (daddr_t), num_blocks, fsys) != num_blocks){
  734. X        error (errno, "\nerror reading indirect block %ld\n", block);
  735. X        /* NOTREACHED */
  736. X        }
  737. X    pos = cur_pos;
  738. X
  739. X    /*
  740. X     * scan the data blocks looking for numbers out of sequence
  741. X     */
  742. X    for (i = 0; i < num_blocks; i++){
  743. X        new_pos = indirect_blk [i];
  744. X        if (new_pos == 0){
  745. X            return pos;
  746. X            }
  747. X        data->data_blocks++;
  748. X        data->total_blocks++;
  749. X        data->potential_seeks++;
  750. X        if (new_pos != pos + 1){
  751. X            data->seeks++;
  752. X            }
  753. X        pos = new_pos;
  754. X        }
  755. X    return pos;
  756. X    }
  757. X
  758. X/*
  759. X * check_double_indirects : scans a block containing a list of indirect
  760. X * blocks, checking for data block numbers that are out of sequence.
  761. X */
  762. Xdaddr_t check_double_indirects (block, cur_pos, data)
  763. Xdaddr_t block;                    /* indirect block to check */
  764. Xdaddr_t cur_pos;                /* current block offset */
  765. Xstruct file_data *data;                /* current file statistics */
  766. X{
  767. X    daddr_t dindirect_blk[256];        /* holds a double-indirect
  768. X                         * block */
  769. X    int i;                    /* loop counter */
  770. X    int num_blocks;                /* number of indirect blocks
  771. X                         * in a d-i block */
  772. X
  773. X    num_blocks = 128 * fs_type;
  774. X    data->total_blocks++;
  775. X
  776. X    /*
  777. X     * the double-indirect block itself should be in sequence with the
  778. X     * data blocks
  779. X     */
  780. X    data->potential_seeks++;
  781. X    if (block != cur_pos + 1){
  782. X        data->seeks++;
  783. X        }
  784. X
  785. X    /*
  786. X     * get the d-i block
  787. X     */
  788. X    if (fseek (fsys, block * 512L * fs_type, 0)){
  789. X        error (errno, "\nerror seeking double indirect block %ld\n",
  790. X             block);
  791. X        /* NOTREACHED */
  792. X        }
  793. X    if (fread (dindirect_blk, sizeof (daddr_t), num_blocks, fsys) != num_blocks){
  794. X        error (errno, "\nerror reading double indirect block %ld\n",
  795. X             block);
  796. X        /* NOTREACHED */
  797. X        }
  798. X
  799. X    /*
  800. X     * scan through the d-i block
  801. X     */
  802. X    for (i = 0; i < num_blocks; i++){
  803. X        if (dindirect_blk[i] == 0){
  804. X            break;
  805. X            }
  806. X        cur_pos = check_indirects (dindirect_blk[i],
  807. X                       block,
  808. X                       data);
  809. X        }
  810. X    return cur_pos;
  811. X    }
  812. X
  813. X/*
  814. X * check_triple_indirects : scans a block containing a list of double
  815. X * indirect blocks, looking for data block numbers that are out of sequence.
  816. X */
  817. Xdaddr_t check_triple_indirects (block, cur_pos, data)
  818. Xdaddr_t block;                    /* indirect block to check */
  819. Xdaddr_t cur_pos;                /* current block offset */
  820. Xstruct file_data *data;                /* current file statistics */
  821. X{
  822. X    daddr_t tindirect_blk[256];        /* holds a triple-indirect
  823. X                         * block */
  824. X    int i;                    /* loop counter */
  825. X    int num_blocks;                /* number of double-indirect
  826. X                         * blocks in a triple-i blk */
  827. X
  828. X
  829. X    num_blocks = 128 * fs_type;
  830. X    data->total_blocks++;
  831. X
  832. X    /*
  833. X     * the triple-indirect block itself should be in sequence with the
  834. X     * data blocks
  835. X     */
  836. X    data->potential_seeks++;
  837. X    if (block != cur_pos + 1){
  838. X        data->seeks++;
  839. X        }
  840. X
  841. X    /*
  842. X     * get the t-i block
  843. X     */
  844. X    if (fseek (fsys, block * 512L * fs_type, 0)){
  845. X        error (errno, "\nerror seeking triple indirect block %ld\n",
  846. X             block);
  847. X        /* NOTREACHED */
  848. X        }
  849. X    if (fread (tindirect_blk, sizeof (daddr_t), num_blocks, fsys) != num_blocks){
  850. X        error (errno, "\nerror reading triple indirect block %ld\n",
  851. X             block);
  852. X        /* NOTREACHED */
  853. X        }
  854. X
  855. X    /*
  856. X     * scan through the t-i block
  857. X     */
  858. X    for (i = 0; i < num_blocks; i++){
  859. X        if (tindirect_blk[i] == 0){
  860. X            break;
  861. X            }
  862. X        cur_pos = check_double_indirects (tindirect_blk[i],
  863. X                          block,
  864. X                          data);
  865. X        }
  866. X    return cur_pos;
  867. X    }
  868. X
  869. X/*
  870. X * check_file : scans the data block numbers of an i-node, looking for
  871. X * block numbers that are out of sequence, and would thus result in excess
  872. X * track-to-track seeking.  This function also checks directory files for
  873. X * indirection (more than 10 data blocks), and performs a simple consistency
  874. X * check on all file sizes
  875. X */
  876. Xvoid check_file (inode, inode_number, data)
  877. Xstruct dinode *inode;                /* inode info structure */
  878. Xint inode_number;                /* inode number to be
  879. X                         * checked */
  880. Xstruct file_data *data;                /* current file statistics */
  881. X{
  882. X    daddr_t pos;                /* current block */
  883. X    daddr_t new_pos;            /* next block in file */
  884. X    int i;                    /* loop counter */
  885. X    long file_size;                /* file size computed by
  886. X                         * actual byte count */
  887. X
  888. X    pos = blk_no (&inode->di_addr[0]);    /* first data block */
  889. X
  890. X    if (inode->di_size == 0 || pos == 0)return; /* ignore 0-size files */
  891. X
  892. X    data->data_blocks = data->total_blocks = 1;
  893. X
  894. X    /*
  895. X     * do some simple-minded statistics gathering
  896. X     */
  897. X    if (FILE_TYPE (inode) == S_IFDIR){ /* got a directory */
  898. X        num_directories++;
  899. X        }
  900. X    if (inode->di_nlink > 1){        /* multi-linked files */
  901. X        linked_files++;
  902. X        }
  903. X
  904. X    /*
  905. X     * scan the data blocks looking for numbers out of sequence
  906. X     */
  907. X    for (i = 1; i < 10; i++){
  908. X        new_pos = blk_no (&inode->di_addr[i*3]);
  909. X        if (new_pos == 0){        /* end of file */
  910. X            break;
  911. X            }
  912. X        data->data_blocks++;
  913. X        data->total_blocks++;
  914. X        data->potential_seeks++;
  915. X        if (new_pos != pos + 1){    /* out of sequence ? */
  916. X            data->seeks++;
  917. X            }
  918. X        pos = new_pos;
  919. X        }
  920. X
  921. X    /*
  922. X     * block 10, if non-zero, is the number of the block which contains
  923. X     * the next (128 * fs_type) data block numbers.  It should also be
  924. X     * in sequence with the data blocks.  Block 10 is called an
  925. X     * "indirect" block.
  926. X     */
  927. X    if (blk_no (&inode->di_addr[10*3])){
  928. X        indirects++;
  929. X
  930. X        /*
  931. X         * if a directory contains indirection, it is too large for
  932. X         * efficient access.  Report it.
  933. X         */
  934. X        if (FILE_TYPE (inode) == S_IFDIR){
  935. X            printf ("inode %d is a large directory\n", inode_number);
  936. X            big_directories++;
  937. X            }
  938. X        pos = check_indirects (blk_no (&inode->di_addr[10*3]),
  939. X                       pos,
  940. X                       data);
  941. X        }
  942. X
  943. X    /*
  944. X     * block 11, if non-zero, is the number of the block which contains
  945. X     * the next (128 * fs_type) INDIRECT block numbers.  It should also be
  946. X     * in sequence with the data blocks.  Block 11 is called a "double-
  947. X     * indirect" block.
  948. X     */
  949. X    if (blk_no (&inode->di_addr[11*3])){
  950. X        double_indirects++;
  951. X        if (report_indirects){
  952. X            printf ("double indirection : %d\n", inode_number);
  953. X            }
  954. X        pos = check_double_indirects (blk_no (&inode->di_addr[11*3]),
  955. X                          pos,
  956. X                          data);
  957. X        }
  958. X
  959. X    /*
  960. X     * block 12, if non-zero, is the number of the block which contains
  961. X     * the next (128 * fs_type) DOUBLE-INDIRECT block numbers.  It should
  962. X     * also be in sequence with the data blocks.  Block 12 is called a
  963. X     * "triple-indirect" block.
  964. X     */
  965. X    if (blk_no (&inode->di_addr[12*3])){
  966. X        triple_indirects++;
  967. X        if (report_indirects){
  968. X            printf ("triple indirection : %d\n", inode_number);
  969. X            }
  970. X        pos = check_triple_indirects (blk_no (&inode->di_addr[12*3]),
  971. X                          pos,
  972. X                          data);
  973. X        }
  974. X
  975. X    /*
  976. X     * do a simple check to detect possible file-size errors (a la
  977. X     * fsck phase 1)
  978. X     */
  979. X    file_size = (inode->di_size + (512 * fs_type - 1)) / (512 * fs_type);
  980. X    if (file_size != data->data_blocks){
  981. X        size_errors++;
  982. X        if (report_errors){
  983. X            printf ("inode %d, inconsistent file size : actual blocks = %ld, computed = %ld (%ld bytes)\n",
  984. X                inode_number, data->data_blocks, 
  985. X                file_size, inode->di_size);
  986. X            }
  987. X        }
  988. X    }
  989. X
  990. X/*
  991. X * log_stats : updates global statistics based on the current file statistics.
  992. X * The current file is then checked to see if it qualifies as one of the 10
  993. X * worst offenders (i.e., most fragmented) encountered thus far.  The 10 worst
  994. X * offenders are determined based on their absolute number of disk seeks
  995. X * required to read the entire file.  Such an absolute test (viz a viz a
  996. X * relative percentage test) ensures that very small, but fragmented, files
  997. X * will not clutter the output.
  998. X */
  999. Xvoid log_stats (data)
  1000. Xstruct file_data *data;                /* file statistics to be
  1001. X                         * logged */
  1002. X{
  1003. X    int i, j;                /* loop counters */
  1004. X
  1005. X
  1006. X    /*
  1007. X     * update global statistics
  1008. X     */
  1009. X    blocks += data->total_blocks;
  1010. X    potential_seeks += data->potential_seeks;
  1011. X    seeks += data->seeks;
  1012. X    data->fragm = data->potential_seeks ? (float)data->seeks/(float)data->potential_seeks : 0.0;
  1013. X
  1014. X    /*
  1015. X     * update 10 worst offender array
  1016. X     */
  1017. X    for (i = 0; i < 10; i++){
  1018. X        if (data->seeks > file_log[i].seeks){
  1019. X            for (j = 9; j > i; j--){
  1020. X                file_log[j] = file_log[j-1];
  1021. X                }
  1022. X            file_log[i] = *data;
  1023. X            break;
  1024. X            }
  1025. X        }
  1026. X    }
  1027. X
  1028. X/*
  1029. X * scan : scan through each i-node of a file system, compiling statistics
  1030. X * regarding fragmentation and indirection.
  1031. X */
  1032. Xvoid scan (){
  1033. X    int    i, j;                /* loop counters */
  1034. X    struct dinode i_node[I_BLOCK_FACTOR];    /* holds a block of inodes */
  1035. X    struct file_data data;            /* per-inode statistics */
  1036. X
  1037. X    for (i = 1; i < num_inodes; i+=I_BLOCK_FACTOR){
  1038. X
  1039. X        /*
  1040. X         * for efficiency, read a block of i-nodes at a time
  1041. X         */
  1042. X        get_inodes (i, i_node, I_BLOCK_FACTOR);
  1043. X
  1044. X        /*
  1045. X         * scan through each i-node that was read in
  1046. X         */
  1047. X        for (j = 0; i+j < num_inodes && j < I_BLOCK_FACTOR; j++){
  1048. X            if (debug){
  1049. X                printf ("inode %d\r", i+j);
  1050. X                }
  1051. X            if (i+j <= 1)continue;    /* don't scan i-node 1 */
  1052. X            if (i_node[j].di_mode != 0){ /* unused i-node ? */
  1053. X                init_stats (&data, i+j);
  1054. X                check_file (&i_node[j], i+j, &data); /* scan blocks in file */
  1055. X                log_stats (&data);
  1056. X                }
  1057. X            else {
  1058. X                free_inodes++;
  1059. X                }
  1060. X            }
  1061. X        }
  1062. X    }
  1063. X
  1064. X/*
  1065. X * print_report : calculates percentages and prints a summary report of
  1066. X * file system statistics
  1067. X */
  1068. Xvoid print_report (){
  1069. X    long    num_files;            /* number of inodes used
  1070. X                         * in file system */
  1071. X    int    i;                /* loop counter */
  1072. X    
  1073. X    float    fragm,                /* percent fragmentation */
  1074. X        ind_p,                /* percent indirections */
  1075. X        dind_p,                /* percent double indirects */
  1076. X        tind_p,                /* percent triple indirects */
  1077. X        bused_p,            /* percent data blocks used */
  1078. X        iused_p,            /* percent inodes used */
  1079. X        bdir_p;                /* percent of directories
  1080. X                         * that have more than 10
  1081. X                         * blocks */
  1082. X
  1083. X    /*
  1084. X     * calculate percentages for report
  1085. X     */
  1086. X    fragm = potential_seeks ? (float)seeks/(float)potential_seeks : 0.0;
  1087. X    bused_p = (float)blocks/(float)(blocks+super.s_tfree);
  1088. X    num_files = num_inodes - free_inodes;
  1089. X    iused_p = (float)num_files/(float)num_inodes;
  1090. X    ind_p = num_files ? (float)indirects/(float)num_files : 0.0;
  1091. X    dind_p = num_files ? (float)double_indirects/(float)num_files : 0.0;
  1092. X    tind_p = num_files ? (float)triple_indirects/(float)num_files : 0.0;
  1093. X    bdir_p = num_directories ? (float)big_directories/(float)num_directories : 0.0;
  1094. X
  1095. X    /*
  1096. X     * print out report
  1097. X     */
  1098. X    printf ("\n\nFile system name = \"%.6s\", Volume name = \"%.6s\"\n",
  1099. X        super.s_fname, super.s_fpack);
  1100. X    printf ("File system logical block size = %d bytes\n", 512 * fs_type);
  1101. X    printf ("Volume Size = %ld blocks (%ld bytes)\n",
  1102. X        super.s_fsize, super.s_fsize * 512L * fs_type);
  1103. X    printf ("\t%u blocks reserved for super block and inodes\n", super.s_isize);
  1104. X    printf ("\t%lu blocks reserved for data\n", 
  1105. X        super.s_fsize - super.s_isize);
  1106. X    printf ("Total inodes = %d\n", num_inodes);
  1107. X    printf ("%.2f%% inodes used (%ld used, %ld free)\n", 
  1108. X        iused_p*100, num_inodes - free_inodes, free_inodes);
  1109. X    printf ("%.2f%% data blocks used (%ld used, %ld free)\n",
  1110. X        bused_p*100, blocks, super.s_tfree);
  1111. X    printf ("%d directories\n", num_directories);
  1112. X    printf ("%d multiply-linked files\n", linked_files);
  1113. X    printf ("\nFragmentation         = %.2f%%\n", fragm*100);
  1114. X/*    printf ("(%ld seeks of %ld potential)\n", seeks, potential_seeks); */
  1115. X    printf ("Indirects             = %ld (%.2f%%)\n",
  1116. X        indirects, ind_p*100);
  1117. X    printf ("Double indirects      = %ld (%.2f%%)\n",
  1118. X        double_indirects, dind_p*100);
  1119. X    printf ("Triple indirects      = %ld (%.2f%%)\n",
  1120. X        triple_indirects, tind_p*100);
  1121. X    printf ("Oversized directories = %d (%.2f%%)\n",
  1122. X        big_directories, bdir_p*100);
  1123. X    printf ("10 worst offenders:\n");
  1124. X    printf ("   i-node   Size  Fragments    %%\ti-node   Size  Fragments    %%\n");
  1125. X    for (i = 0; i < 5; i++){
  1126. X        if (file_log[i].inode != 0){
  1127. X            printf ("   %6d %6ld   %6ld   %6.2f%%",
  1128. X                file_log[i].inode,
  1129. X                file_log[i].data_blocks,
  1130. X                file_log[i].seeks+1,
  1131. X                file_log[i].fragm*100);
  1132. X            if (file_log[i+5].inode != 0){
  1133. X                printf ("\t%6d %6ld   %6ld   %6.2f%%",
  1134. X                    file_log[i+5].inode,
  1135. X                    file_log[i+5].data_blocks,
  1136. X                    file_log[i+5].seeks+1,
  1137. X                    file_log[i+5].fragm*100);
  1138. X                }
  1139. X            printf ("\n");
  1140. X            }
  1141. X        else break;
  1142. X        }
  1143. X    }
  1144. X
  1145. X/*
  1146. X * anal_file : analyzes a single file for fragmentation.
  1147. X */
  1148. Xvoid anal_file (ino, fname)
  1149. Xint ino;                    /* i-node number */
  1150. Xchar *fname;                    /* filename of this inode */
  1151. X{
  1152. X    struct file_data data;            /* current file statistics */
  1153. X
  1154. X    struct dinode i_node;            /* current inode data */
  1155. X
  1156. X    get_inodes (ino, &i_node, 1);
  1157. X    init_stats(&data, ino);
  1158. X    check_file (&i_node, ino, &data);
  1159. X    log_stats (&data);
  1160. X    printf ("   %-14s\t%6d    %6ld   %6ld   %6.2f%%\n",
  1161. X        fname, data.inode, data.seeks+1, 
  1162. X                       data.total_blocks, data.fragm*100);
  1163. X    }
  1164. X
  1165. Xmain (argc, argv)
  1166. Xint argc;
  1167. Xchar *argv[];
  1168. X{
  1169. X    int next_param;
  1170. X    struct stat f_stat;
  1171. X
  1172. X    /*
  1173. X     * perform various initialization functions
  1174. X     */
  1175. X    next_param = init (argc, argv);
  1176. X
  1177. X    if (next_param == argc){
  1178. X        /*
  1179. X         * no individual files to check, scan entire file system
  1180. X         */
  1181. X        printf ("Analyzing file system %s...\n", special);
  1182. X
  1183. X        /*
  1184. X         * scan through all i-nodes in the file system
  1185. X         */
  1186. X        scan();
  1187. X
  1188. X        /*
  1189. X         * print out statistics summary
  1190. X         */
  1191. X        print_report();
  1192. X        }
  1193. X    else {
  1194. X        /*
  1195. X         * scan individual files instead of entire file system
  1196. X         */
  1197. X        printf ("        Name      \ti-node    Fragments  Size      %%\n");
  1198. X        for (; next_param < argc; next_param++){
  1199. X            if (stat (argv[next_param], &f_stat) != 0){
  1200. X                error (errno, "error opening \"%s\"\n",
  1201. X                       argv[next_param]);
  1202. X                }
  1203. X            else {
  1204. X                if (!IS_SPECIAL (f_stat.st_mode)){
  1205. X                    anal_file (f_stat.st_ino, argv[next_param]);
  1206. X                    }
  1207. X                }
  1208. X            }
  1209. X        }
  1210. X    }
  1211. END_OF_fsanalyze.c
  1212. if test 25225 -ne `wc -c <fsanalyze.c`; then
  1213.     echo shar: \"fsanalyze.c\" unpacked with wrong size!
  1214. fi
  1215. # end of overwriting check
  1216. fi
  1217. echo shar: End of archive 1 \(of 1\).
  1218. cp /dev/null ark1isdone
  1219. MISSING=""
  1220. for I in 1 ; do
  1221.     if test ! -f ark${I}isdone ; then
  1222.     MISSING="${MISSING} ${I}"
  1223.     fi
  1224. done
  1225. if test "${MISSING}" = "" ; then
  1226.     echo You have unpacked all 1 archives.
  1227.     rm -f ark[1-9]isdone
  1228. else
  1229.     echo You still need to unpack the following archives:
  1230.     echo "        " ${MISSING}
  1231. fi
  1232. ##  End of shell archive.
  1233. exit 0
  1234. --
  1235. Mike Young - Software Development Technologies, Inc., Sudbury MA 01776
  1236. UUCP     : {decvax,harvard,linus,mit-eddie}!necntc!necis!mrst!sdti!mjy
  1237. Internet : mjy%sdti.uucp@harvard.harvard.edu      Tel: +1 617 443 5779
  1238. "What would you do with a brain if you had one?" -- Dorothy, Wiz of Oz
  1239.